home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 42
/
Amiga Format AFCD42 (Issue 126, Aug 1999).iso
/
-serious-
/
comms
/
other
/
slrn
/
slrn_src
/
src
/
uudecode.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-14
|
22KB
|
1,106 lines
/* -*- mode: C; mode: fold; -*- */
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
*
* This file is part of slrn.
*
* Slrn is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Slrn is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with Slrn; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "slrnfeat.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <slang.h>
#define MAX_ARTICLE_LINE_LEN 4096
#include "uudecode.h"
#include "util.h"
#include "ttymsg.h"
#include "slrndir.h"
#ifdef STANDALONE
# include <stdarg.h>
# if SLRN_HAS_PIPING
# define SLRN_POPEN uudecode_popen
# define SLRN_PCLOSE uudecode_pclose
# endif
# define slrn_message_now slrn_tty_message
# define slrn_message slrn_tty_message
static FILE *uudecode_popen (char *cmd, char *mode) /*{{{*/
{
# if SLRN_HAS_PIPING
return popen (cmd, mode);
# else
slrn_error ("Piping not implemented on this system.");
return NULL;
# endif
}
/*}}}*/
static int uudecode_pclose (FILE *fp) /*{{{*/
{
# if SLRN_HAS_PIPING
return pclose (fp);
# else
return -1;
# endif
}
/*}}}*/
#else
# include <slang.h>
# include "jdmacros.h"
# include "slrn.h"
# include "misc.h"
# include "uudecode.h"
# define SLRN_POPEN slrn_popen
# define SLRN_PCLOSE slrn_pclose
char *Slrn_Decode_Directory;
#endif
#ifdef VMS
# include "vms.h"
#endif
static int uudecode_fclose (FILE *fp, FILE *pipe_fp) /*{{{*/
{
if ((fp == pipe_fp) || (fp == NULL))
return 0;
#ifdef STANDALONE
if (0 == fclose (fp)) return 0;
slrn_error ("Error closing file. File system full?");
return -1;
#else
return slrn_fclose (fp);
#endif
}
/*}}}*/
static int unpack_as_shell_archive (FILE *fp, char *buf, int size) /*{{{*/
{
FILE *pp;
size--;
pp = SLRN_POPEN ("/bin/sh", "w");
if (pp == NULL)
{
slrn_error ("Unable to open /bin/sh\n");
return -1;
}
while (fgets (buf, size, fp) != NULL)
{
fputs (buf, pp);
if (!strcmp (buf, "exit 0\n"))
break;
}
if (-1 == SLRN_PCLOSE (pp))
{
slrn_error ("Error encountered while processing shell archive.\n");
return -1;
}
return 0;
}
/*}}}*/
static FILE *open_output_file (char *name, char *type, int mode, FILE *use_this) /*{{{*/
{
FILE *fp;
if (use_this != NULL)
return use_this;
fp = fopen (name, "wb");
if (fp == NULL)
{
slrn_error("Unable to create %s\n", name);
return NULL;
}
slrn_message_now ("creating %s (%s)\n", name, type);
if (mode != -1)
chmod (name, mode);
return fp;
}
/*}}}*/
static unsigned char Base64_Table [256];
static void initialize_base64 (void) /*{{{*/
{
int i;
for (i = 0; i < 256; i++) Base64_Table[i] = 0xFF;
for (i = 'A'; i <= 'Z'; i++) Base64_Table[i] = (unsigned char) (i - 'A');
for (i = 'a'; i <= 'z'; i++) Base64_Table[i] = 26 + (unsigned char) (i - 'a');
for (i = '0'; i <= '9'; i++) Base64_Table[i] = 52 + (unsigned char) (i - '0');
Base64_Table['+'] = 62;
Base64_Table['/'] = 63;
}
/*}}}*/
/* returns 0 if entire line was decoded, or 1if line appears to be padded, or
* -1 if line looks bad.
*/
/* Calling routine guarantees at least 4 characters in line and multiple of 4 */
static int base64_decode_line (char *line, FILE *fp) /*{{{*/
{
unsigned char ch;
unsigned char ch1;
unsigned char bytes[3];
unsigned char *p;
p = (unsigned char *) line;
/* Perform simple syntax check. The loop following this one
* assumes this.
*/
while ((ch = *p++) != 0)
{
if (Base64_Table[ch] == 0xFF)
return -1;
ch = *p++;
if (Base64_Table[ch] == 0xFF)
return -1;
ch = *p++;
if ((Base64_Table[ch] == 0xFF) && (ch != '='))
{
return -1;
}
ch = *p++;
if ((Base64_Table[ch] == 0xFF) && (ch != '='))
{
return -1;
}
}
while ((ch = (unsigned char) *line++) != 0)
{
ch1 = Base64_Table[ch];
bytes[0] = ch1 << 2;
ch = *line++;
ch1 = Base64_Table[ch];
bytes[0] |= ch1 >> 4;
bytes[1] = ch1 << 4;
ch = *line++;
ch1 = Base64_Table[ch];
if (ch1 == 0xFF)
{
fwrite (bytes, 1, 1, fp);
return 1;
}
bytes[1] |= ch1 >> 2;
bytes[2] = ch1 << 6;
ch = *line++;
ch1 = Base64_Table[ch];
if (ch1 == 0xFF)
{
fwrite (bytes, 1, 2, fp);
return 1;
}
bytes[2] |= ch1;
fwrite (bytes, 1, 3, fp);
}
return 0;
}
/*}}}*/
static char Base64_Filename[256];
static int Base64_Unknown_Number;
/* Returns 1 if padded line which indicates end of encoded file, 0 if
* decoded something or -1 if nothing.
*/
static int decode_base64 (FILE *fp, FILE *fpout, char *line, unsigned int buflen) /*{{{*/
{
int decoding = 0;
unsigned int len;
int ret;
while (NULL != fgets (line, buflen, fp))
{
if (Base64_Table[(unsigned char) *line] == 0xFF)
{
if (decoding) return 0;
else return -1;
}
len = strlen (line);
if (len)
{
if (line [len - 1] == '\n')
{
line[len - 1] = 0;
len--;
}
}
if ((len % 4) != 0)
{
if (decoding) return 0;
else return -1;
}
ret = base64_decode_line (line, fpout);
if (ret)
{
if ((ret == -1) && decoding) ret = 0;
return ret;
}
decoding = 1;
}
return 0;
}
/*}}}*/
static char *skip_whitespace (char *p) /*{{{*/
{
while ((*p == ' ') || (*p == '\t') || (*p == '\n')) p++;
return p;
}
/*}}}*/
static char *skip_header_string (char *p, char *name) /*{{{*/
{
unsigned int len;
p = skip_whitespace (p);
len = strlen (name);
if (0 != slrn_case_strncmp ((unsigned char *)p, (unsigned char *)name, len))
return NULL;
return p + len;
}
/*}}}*/
static char *skip_beyond_name_eqs (char *p, char *name) /*{{{*/
{
int ch;
unsigned int len;
len = strlen (name);
while (1)
{
p = skip_whitespace (p);
if (*p == 0) return NULL;
if (0 != slrn_case_strncmp ((unsigned char *) p, (unsigned char *) name, len))
{
while (((ch = *p) != 0) && (ch != ' ') && (ch != '\t') && (ch != '\n'))
p++;
continue;
}
p = skip_whitespace (p + len);
if (*p != '=') continue;
p = skip_whitespace (p + 1);
if (*p == 0)
return NULL;
return p;
}
}
/*}}}*/
static int parse_name_eqs_int (char *p, char *name, int *val) /*{{{*/
{
int ch;
int ival;
p = skip_beyond_name_eqs (p, name);
if (p == NULL) return -1;
ival = 0;
while (((ch = *p) != 0) && isdigit(ch))
{
ival = ival * 10 + (ch - '0');
p++;
}
*val = ival;
return 0;
}
/*}}}*/
static int parse_name_eqs_string (char *p, char *name, char *str, unsigned int len) /*{{{*/
{
char ch;
char *pmax;
int quote = 0;
p = skip_beyond_name_eqs (p, name);
if (p == NULL) return -1;
if (*p == '"')
{
quote = 1;
p++;
}
pmax = (p + len) - 1;
while ((p < pmax)
&& ((ch = *p) != '"')
&& (ch != '\n')
&& (ch != 0))
{
if ((quote == 0) && ((ch == ' ') || (ch == '\t')))
break;
*str++ = ch;
p++;
}
*str = 0;
return 0;
}
/*}}}*/
static void parse_content_disposition (char *p) /*{{{*/
{
(void) parse_name_eqs_string (p, "filename", Base64_Filename, sizeof (Base64_Filename));
}
/*}}}*/
static int is_encoding_base64 (char *p) /*{{{*/
{
p = skip_whitespace (p);
if (slrn_case_strncmp ((unsigned char *)p, (unsigned char *)"base64", 6))
return 0;
return 1;
}
/*}}}*/
/* Looking for message/pa